import { constantRoutes } from "@/router"
import MenuApi from "@/api/MenuApi"
import { ComponentMap } from "@/utils/get-component"
import Layout from "@/layout"

/**
 * Use meta.role to determine if the current user has permission
 * @param permissions {String[]} {AuthorityCode}
 * @param route {Route}
 */
function hasPermission(permissions, route) {
  if (route.meta && route.meta.permissions) {
    return permissions.some(permission => route.meta.permissions.includes(permission))
  } else {
    return true
  }
}

/**
 * Filter asynchronous routing tables by recursion
 * @param routes {Route[]} generateRoutes
 * @param permissions {String[]}
 */
function filterGenerateRoutes(routes, permissions) {
  return routes
    .map(route => {
      const tmp = { ...route }
      if (hasPermission(permissions, tmp)) {
        if (tmp.children) {
          tmp.children = filterGenerateRoutes(tmp.children, permissions)
        }
        return tmp
      }
      return null
    })
    .filter(Boolean)
}

function buildRoutes(tree) {
  return tree.map(item => {
    // 没有子元素的目录不构建
    if (!item.menuType && (!item.children || item.children.length === 0)) return null

    const component = item.menuType ? ComponentMap[item.routeName] : Layout
    const permissions = []
    if (item.permission) permissions.push(item.permission)
    const route = {
      path: item.menuType ? item.routePath.replace("/", "") : `/${item.routePath.replace("/", "")}`,
      name: item.routeName,
      component,
      meta: { title: item.menuName, icon: item.iconName, noCache: !item.cached, permissions }
    }
    if (item.children && item.children.length > 0) {
      route.redirect = `/${item.routePath.replace("/", "")}/${item.children[0].routePath.replace("/", "")}`
      route.meta.permissions.push(...item.children.map(i => i.permission).filter(Boolean))
      route.children = buildRoutes(item.children)
    }
    return route
  }).filter(Boolean)
}

const permission = {
  state: {
    routes: [],
    addRoutes: []
  },
  mutations: {
    SET_ROUTES: (state, routes) => {
      state.routes = constantRoutes.concat(routes)
      state.addRoutes = routes
    }
  },
  actions: {
    /**
     * 生成异步挂载路由
     * @param commit
     * @param permissions {String[]}
     * @returns {Promise<unknown>}
     */
    generateRoutes({ commit }, permissions) {
      return new Promise(resolve => {
        MenuApi.getRoute().then(res => {
          let routes = buildRoutes(res.data)
          routes.push({ path: "*", redirect: "/404", hidden: true })
          let accessedRoutes
          if (permissions.includes("*")) {
            accessedRoutes = routes || []
          } else {
            accessedRoutes = filterGenerateRoutes(routes, permissions)
          }
          commit("SET_ROUTES", accessedRoutes)
          resolve(accessedRoutes)
        })
      })
    }
  }
}

export default permission
